/*
    对前边所有模块进行整合，向外提供完成不同等级日志的输出接口
    日志器模块：
        1. 抽象日志器基类
        2. 派生出不同的日志器子类（同步日志器 && 异步日志器）
*/
#pragma once
#include "sink.hpp"
#include "Util.hpp"
#include "Level.hpp"
#include "format.hpp"
#include "looper.hpp"
#include "message.hpp"
#include <unordered_map>
#include <cstdarg>
#include <atomic>
#include <mutex>

namespace XKL
{
    class Logger
    {
    public:
        using ptr = std::shared_ptr<Logger>;
        Logger(LogLevel::Value level,
               Formatter::ptr& formater, // 用户可能需要传入自定义输出格式，
               const std::string& logger_name,
               std::vector<LogSink::ptr>& sinks)
               : _limit_level(level), _formater(formater), _logger_name(logger_name), _sinks(sinks.begin(), sinks.end())
            {}

        std::string GetLoggerName()
        {
            return _logger_name;
        }

        void debug(const std::string& filename, size_t line, const char* fmt, ...)
        {
            // 1. 判断当前的日志是否达到输出等级
            if(!shouldLog(LogLevel::DEBUG)) return ;
            // 2. 对fmt格式化字符串和不定参进行字符串组织，得到的日志消息的字符串
            va_list ap;
            va_start(ap, fmt);
            char* buff;
            int n = vasprintf(&buff, fmt, ap);

            serialize(LogLevel::DEBUG, filename, line, buff);
            free(buff);
        }
        void info(const std::string& filename, size_t line, const char* fmt, ...)
        {
            if(!shouldLog(LogLevel::INFO)) return ;
            va_list ap;
            va_start(ap, fmt);
            char* buff;
            int n = vasprintf(&buff, fmt, ap);

            serialize(LogLevel::INFO, filename, line, buff);
            free(buff);
        }
        void warn(const std::string& filename, size_t line, const char* fmt, ...)
        {
            if(!shouldLog(LogLevel::WARN)) return ;
            va_list ap;
            va_start(ap, fmt);
            char* buff;
            int n = vasprintf(&buff, fmt, ap);

            serialize(LogLevel::WARN, filename, line, buff);
            free(buff);
        }
        void error(const std::string& filename, size_t line, const char* fmt, ...)
        {
            if(!shouldLog(LogLevel::ERROR)) return ;
            va_list ap;
            va_start(ap, fmt);
            char* buff;
            int n = vasprintf(&buff, fmt, ap);

            serialize(LogLevel::ERROR, filename, line, buff);
            free(buff);
        }
        void fatal(const std::string& filename, size_t line, const char* fmt, ...)
        {
            if(!shouldLog(LogLevel::FATAL)) return ;
            va_list ap;
            va_start(ap, fmt);
            char* buff;
            int n = vasprintf(&buff, fmt, ap);

            serialize(LogLevel::FATAL, filename, line, buff);
            free(buff);
        }
    protected:
        bool shouldLog(LogLevel::Value level) { return level >= _limit_level; }
        void serialize(LogLevel::Value level ,const std::string& filename, size_t line, const std::string& buff)
        {
            // 3. 构造LogMsg对象
            LogMsg msg(level, line, filename, _logger_name, buff);
            // 4. 通过格式化工具对LogMsg进行格式化，得到格式化后的日志字符串
            std::string msgStr = _formater->format(msg);
            // 5. 对消息进行落地
            log(msgStr.c_str(), msgStr.size());
        }
        /*不同的日志器会有不同的实际落地方式*/
        virtual void log(const char* data, size_t len) = 0; // ???

    protected:
        std::mutex _mtx;
        Formatter::ptr _formater;
        std::string _logger_name;
        std::vector<LogSink::ptr> _sinks;
        std::atomic<LogLevel::Value> _limit_level;
    };

    class SyncLogger : public Logger
    {
    public:
        SyncLogger(LogLevel::Value level,
                   Formatter::ptr& formater, 
                   const std::string& logger_name,
                   std::vector<LogSink::ptr>& sinks)
                    : Logger(level, formater, logger_name, sinks)
                {}
    
    protected:
        void log(const char* data, size_t len)
        {
            std::unique_lock<std::mutex> lock(_mtx); // ??
            if(_sinks.empty()) return ;

            for(auto& sink: _sinks)
            {
                sink->Log(data, len);
            }   
        }
    };
    
    class AsyncLogger : public Logger
    {
    public:
        AsyncLogger(AsyncType looper_type,
                    LogLevel::Value level,
                    Formatter::ptr& formater, 
                    const std::string& logger_name,
                    std::vector<LogSink::ptr>& sinks)
                     : Logger(level, formater, logger_name, sinks) 
                     , _looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::RealLog, this, std::placeholders::_1), looper_type))
                {}

        void log(const char* data, size_t len) override
        {
            _looper->Push(data, len);
        }

        void RealLog(Buffer& buff)
        {
            // 单执行流的串行化访问，无须加锁
            if(_sinks.empty()) return ;

            for(auto& sink: _sinks)
            {
                sink->Log(buff.begin(), buff.ReadAbleSize());
            }   
        }
    private:
        AsyncLooper::ptr _looper;
    };

    /*使用建造者模式来创建日志器，而不是让用户直接去构造日志器，简化用户的使用复杂度*/
    enum LoggerType
    {
        LOGGER_SYNC,
        LOGGER_ASYNC
    };
    // 建造者基类
    class LoggerBuilder
    {
    public:
        LoggerBuilder()
            : _logger_type(LoggerType::LOGGER_SYNC), _limit_level(LogLevel::DEBUG), _looper_type(AsyncType::ASYNC_SAFE) // 默认设置
        {}
        void BuildLoggerType(LoggerType type)
        {
            _logger_type = type;
        }
        void BuildLoggerLevel(LogLevel::Value level)
        {
            _limit_level = level;
        }
        void BuildLoggerName(const std::string& name)
        {
            _logger_name = name;
        }
        void BuildFormater(const std::string& pattern)
        {
            _formater = std::make_shared<Formatter>(pattern);
        }
        void EnableUnsafeAsync()
        {
            _looper_type = AsyncType::ASYNC_UNSAFE;
        }
        template<class SinkType, class ...Args>
        void BuildSink(Args&& ...args)
        {
            _sinks.push_back(std::make_shared<SinkType>(std::forward<Args>(args)...));
        }

        virtual Logger::ptr Build() = 0;
    protected:
        AsyncType _looper_type;
        LoggerType _logger_type;
        Formatter::ptr _formater;
        std::string _logger_name;
        LogLevel::Value _limit_level;
        std::vector<LogSink::ptr> _sinks;
    };
    // 局部日志器建造者
    class LocalLoggerBuilder : public LoggerBuilder
    {
    public:
        Logger::ptr Build()
        {
            assert(!_logger_name.empty());
            if(_formater.get() == nullptr)
            {
                _formater = std::make_shared<Formatter>();
            }

            if(_sinks.empty())
            {
                _sinks.push_back(std::make_shared<StdoutSink>());
            }

            if(_logger_type == LOGGER_ASYNC)
            {
                return std::make_shared<AsyncLogger>(_looper_type, _limit_level, _formater, _logger_name, _sinks);
            }

            return std::make_shared<SyncLogger>(_limit_level, _formater, _logger_name, _sinks);
        }
    };
    // 单例日志器管理类
    class LoggerManager
    {
    public:
        static LoggerManager& GetInstance()
        {
            static LoggerManager logM; // 由C++11支持
            return logM;
        }
        void AddLogger(Logger::ptr logger)
        {
            if(HaveLogger(logger->GetLoggerName())) return;
            std::unique_lock<std::mutex> lock(_mtx);
            _loggers[logger->GetLoggerName()] = logger;
        }
        Logger::ptr GetLogger(const std::string& name)
        {
            if(!HaveLogger(name)) return Logger::ptr();
            std::unique_lock<std::mutex> lock(_mtx);
            return _loggers[name];
        }
        Logger::ptr RootLogger()
        {
            std::unique_lock<std::mutex> lock(_mtx);
            return _root_ptr;
        }
        bool HaveLogger(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mtx);
            auto iter = _loggers.find(name);

            return iter != _loggers.end();
        }
    private:
        LoggerManager() 
        {
            // 坚决不能使用全局建造者，否则会出现闭环问题
            std::unique_ptr<LoggerBuilder> builder(new LocalLoggerBuilder);
            builder->BuildLoggerName("root");
            _root_ptr = builder->Build();
        }
        LoggerManager(const LoggerManager&) = delete;
        LoggerManager operator=(const LoggerManager&) = delete;
    private:
        std::mutex _mtx;
        Logger::ptr _root_ptr;
        std::unordered_map<std::string, Logger::ptr> _loggers;
    };
    // 全局日志器建造者：将日志器添加到全局单例管理对象中
    class GlobalLoggerBuilder : public LoggerBuilder
    {
    public:
        Logger::ptr Build() override
        {
            assert(!_logger_name.empty());
            if(_formater.get() == nullptr)
            {
                _formater = std::make_shared<Formatter>();
            }

            if(_sinks.empty())
            {
                _sinks.push_back(std::make_shared<StdoutSink>());
            }   
            Logger::ptr logger;
            if(_logger_type == LOGGER_ASYNC)
            {
                logger = std::make_shared<AsyncLogger>(_looper_type, _limit_level, _formater, _logger_name, _sinks);
            }
            else 
            {
                logger = std::make_shared<SyncLogger>(_limit_level, _formater, _logger_name, _sinks);
            }
            LoggerManager::GetInstance().AddLogger(logger);
            return logger;
        }
    };
}